{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1 基本运算：（+、-、*、/、//、%）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "基本运算中所有实例都以下面的张量a、b为例进行："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "a = tf.random.uniform([2, 3], minval=1, maxval=6,dtype=tf.int32)\n",
    "b = tf.random.uniform([2, 3], minval=1, maxval=6,dtype=tf.int32)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=3, shape=(2, 3), dtype=int32, numpy=\n",
       "array([[1, 4, 5],\n",
       "       [5, 1, 4]])>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=7, shape=(2, 3), dtype=int32, numpy=\n",
       "array([[1, 3, 5],\n",
       "       [3, 5, 2]])>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**（1）加（+）**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=12, shape=(2, 3), dtype=int32, numpy=\n",
       "array([[ 2,  7, 10],\n",
       "       [ 8,  6,  6]])>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.add(a,b)  # 通过add方法执行加操作"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=16, shape=(2, 3), dtype=int32, numpy=\n",
       "array([[ 2,  7, 10],\n",
       "       [ 8,  6,  6]])>"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a + b  # 也可以通过操作符进行"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**（2）减（-）**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=18, shape=(2, 3), dtype=int32, numpy=\n",
       "array([[ 0,  1,  0],\n",
       "       [ 2, -4,  2]])>"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.subtract(a,b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=20, shape=(2, 3), dtype=int32, numpy=\n",
       "array([[ 0,  1,  0],\n",
       "       [ 2, -4,  2]])>"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a - b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**（3）乘法（*）**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=22, shape=(2, 3), dtype=int32, numpy=\n",
       "array([[ 1, 12, 25],\n",
       "       [15,  5,  8]])>"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.multiply(a,b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=24, shape=(2, 3), dtype=int32, numpy=\n",
       "array([[ 1, 12, 25],\n",
       "       [15,  5,  8]])>"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a * b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**（4）除法（/）**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=28, shape=(2, 3), dtype=float64, numpy=\n",
       "array([[1.        , 1.33333333, 1.        ],\n",
       "       [1.66666667, 0.2       , 2.        ]])>"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.divide(a,b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=32, shape=(2, 3), dtype=float64, numpy=\n",
       "array([[1.        , 1.33333333, 1.        ],\n",
       "       [1.66666667, 0.2       , 2.        ]])>"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a/b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**（5）地板除法（//）**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=34, shape=(2, 3), dtype=int32, numpy=\n",
       "array([[1, 1, 1],\n",
       "       [1, 0, 2]])>"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.floor_div(a,b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=38, shape=(2, 3), dtype=int32, numpy=\n",
       "array([[1, 1, 1],\n",
       "       [1, 0, 2]])>"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a // b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**（6）取余（%）**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=115, shape=(2, 2, 3), dtype=int32, numpy=\n",
       "array([[[0, 1, 2],\n",
       "        [0, 0, 2]],\n",
       "\n",
       "       [[0, 1, 2],\n",
       "        [0, 0, 2]]])>"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.mod(b,a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=117, shape=(2, 2, 3), dtype=int32, numpy=\n",
       "array([[[0, 1, 2],\n",
       "        [0, 0, 2]],\n",
       "\n",
       "       [[0, 1, 2],\n",
       "        [0, 0, 2]]])>"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b % a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以看出，对于基本运算加（+）、减（-）、点乘（*）、除（/）、地板除法（//）、取余（%），都是对应元素进行运算。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2 指数、开方、对数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**（1）对数运算**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "TensorFlow提供tf.math.log()方法来求对数，当然，求的是以自然常数$e$为底的对数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=41, shape=(3,), dtype=float32, numpy=array([0.99999994, 2.        , 3.        ], dtype=float32)>"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "e = 2.71828183\n",
    "a = tf.constant([e, e*e, e*e*e])\n",
    "tf.math.log(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=46, shape=(2, 2), dtype=float32, numpy=\n",
       "array([[0., 0.],\n",
       "       [0., 0.]], dtype=float32)>"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c = tf.fill([2,2],1.)\n",
    "tf.math.log(c)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "注意：TensorFlow中没有提供函数实现以其他数值为底的对数运算，例如$lo{g_2}8$, $lg100$。不过，我们可以通过其他方式来求取，记得下面这个高中时学过的公式吗："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$$lo{g_a}b = \\frac{{lo{g_c}b}}{{lo{g_c}a}}$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "所以有："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "f = tf.constant([[1., 9.], [16., 100.]])\n",
    "g = tf.constant([[2., 3.], [2., 10.]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=52, shape=(2, 2), dtype=float32, numpy=\n",
       "array([[0., 2.],\n",
       "       [4., 2.]], dtype=float32)>"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.math.log(f) / tf.math.log(g)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**（2）指数运算**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "g = tf.constant([[2, 3], [2, 10]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=66, shape=(2, 2), dtype=int32, numpy=\n",
       "array([[  4,   9],\n",
       "       [  4, 100]])>"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.pow(g, 2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "也可以直接通过运算符来完成："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=59, shape=(2, 2), dtype=int32, numpy=\n",
       "array([[  4,   9],\n",
       "       [  4, 100]])>"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "g ** 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**（3）开方**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "f = tf.constant([[1., 9.], [16., 100.]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=69, shape=(2, 2), dtype=float32, numpy=\n",
       "array([[ 1.,  3.],\n",
       "       [ 4., 10.]], dtype=float32)>"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.sqrt(f)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "自然常数$e$的指数运算："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [],
   "source": [
    "d = tf.constant([[1.,2.],[3.,4.]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=72, shape=(2, 2), dtype=float32, numpy=\n",
       "array([[ 2.7182817,  7.389056 ],\n",
       "       [20.085537 , 54.598152 ]], dtype=float32)>"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.exp(d)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "注意：对数运算函数log()与指数运算函数在不同的模块中。\n",
    "\n",
    "在我看来，上面提到的指数运算与对数运算不在通知模块以及没有提供以其他自然数为底的对数运算，应该应该是TensorFlow中的遗留问题，希望能够在正式版中得到修正。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3 矩阵相乘"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "a = tf.constant(np.arange(6),shape=(2,3))\n",
    "b = tf.constant(np.arange(6),shape=(3,2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=76, shape=(2, 3), dtype=int32, numpy=\n",
       "array([[0, 1, 2],\n",
       "       [3, 4, 5]])>"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=79, shape=(3, 2), dtype=int32, numpy=\n",
       "array([[0, 1],\n",
       "       [2, 3],\n",
       "       [4, 5]])>"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=82, shape=(2, 2), dtype=int32, numpy=\n",
       "array([[10, 13],\n",
       "       [28, 40]])>"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.matmul(a,b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "矩阵相乘也可以通过符号来操作进行，用“@”表示："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=86, shape=(2, 2), dtype=int32, numpy=\n",
       "array([[10, 13],\n",
       "       [28, 40]])>"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a @ b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里的张量a和b都是二维的，但在实际应用中，数据往往高于二维，这时候怎么应算呢？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = tf.constant(np.arange(12),shape=(2,2,3))\n",
    "b = tf.constant(np.arange(12),shape=(2,3,2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=90, shape=(2, 2, 3), dtype=int32, numpy=\n",
       "array([[[ 0,  1,  2],\n",
       "        [ 3,  4,  5]],\n",
       "\n",
       "       [[ 6,  7,  8],\n",
       "        [ 9, 10, 11]]])>"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=93, shape=(2, 3, 2), dtype=int32, numpy=\n",
       "array([[[ 0,  1],\n",
       "        [ 2,  3],\n",
       "        [ 4,  5]],\n",
       "\n",
       "       [[ 6,  7],\n",
       "        [ 8,  9],\n",
       "        [10, 11]]])>"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=96, shape=(2, 2, 2), dtype=int32, numpy=\n",
       "array([[[ 10,  13],\n",
       "        [ 28,  40]],\n",
       "\n",
       "       [[172, 193],\n",
       "        [244, 274]]])>"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a @ b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以看到，当高于二维的张量进行矩阵相乘时，最终的实现还是二维矩阵相乘，只不过分成了多个二维矩阵，四维张量也是一样的："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = tf.constant(np.arange(24),shape=(2,2,2,3))\n",
    "b = tf.constant(np.arange(24),shape=(2,2,3,2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=104, shape=(2, 2, 2, 2), dtype=int32, numpy=\n",
       "array([[[[  10,   13],\n",
       "         [  28,   40]],\n",
       "\n",
       "        [[ 172,  193],\n",
       "         [ 244,  274]]],\n",
       "\n",
       "\n",
       "       [[[ 550,  589],\n",
       "         [ 676,  724]],\n",
       "\n",
       "        [[1144, 1201],\n",
       "         [1324, 1390]]]])>"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a @ b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4 Broadcasting机制"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上面的所有实例中所用到的张量都是在维度数和形状相同情况下进行，那么，当两个张量维度数或者形状不一样时能不能进行运算呢？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = tf.constant([1,2,3])\n",
    "b = tf.constant(np.arange(12),shape=(2,2,3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=109, shape=(2, 2, 3), dtype=int32, numpy=\n",
       "array([[[ 0,  1,  2],\n",
       "        [ 3,  4,  5]],\n",
       "\n",
       "       [[ 6,  7,  8],\n",
       "        [ 9, 10, 11]]])>"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=111, shape=(2, 2, 3), dtype=int32, numpy=\n",
       "array([[[ 1,  3,  5],\n",
       "        [ 4,  6,  8]],\n",
       "\n",
       "       [[ 7,  9, 11],\n",
       "        [10, 12, 14]]])>"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a + b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=113, shape=(2, 2, 3), dtype=int32, numpy=\n",
       "array([[[ 0,  2,  6],\n",
       "        [ 3,  8, 15]],\n",
       "\n",
       "       [[ 6, 14, 24],\n",
       "        [ 9, 20, 33]]])>"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a * b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以看到，一个一维的张量与一个三维张量进行运算是完全没有问题的，从运算结果上可以看出，相当于是三维张量中的每一行数据与张量a进行运算，为什么可以这样运输呢？这就得益于TensorFlow中的Broadcasting机制。\n",
    "\n",
    "Broadcasting机制解除了只能维度数和形状相同的张量才能进行运算的限制，当两个数组进行算术运算时，TensorFlow的Broadcasting机制首先对维度较低的张量形状数组填充1，从后向前，逐元素比较两个数组的形状，当逐个比较的元素值（注意，这个元素值是指描述张量形状数组的值，不是张量的值）满足以下条件时，认为满足 Broadcasting 的条件：\n",
    "\n",
    "（1）相等\n",
    "\n",
    "（2）其中一个张量形状数组元素值为1。\n",
    "\n",
    "当不满足时进行运算则会抛出 ValueError: frames are not aligne 异常。算术运算的结果的形状的每一元素，是两个数组形状逐元素比较时的最大值。\n",
    "\n",
    "回到上面张量a与b相乘的例子，a的形状是（3，），b的形状是(2, 2, 3)，在Broadcasting机制工作时，首先比较维度数，因为a的维度为1，小于b的维度3，所以填充1，a的形状就变成了（1,1,3），然后从最后端的形状数组元素依次往前比较，先是就是3与3比，结果是相等，接着1与2相比，因为其中一个为1，所以a的形状变成了（1,2,3），继续1与2比较，因为其中一个为1，所以a的形状变成了（2,2,3），a中的数据每一行都填充a原来的数据，也就是[1,2,3]，然后在与b进行运算。\n",
    "\n",
    "当然，在TensorFlow的Broadcasting机制运行过程中，上述操作只是理论的，并不会真正的将a的形状变成（2,2,3,），更不会将每一行填充[1,2,3]，只是虚拟进行操作，真正计算时，依旧是使用原来的张量a。这么做的好处是运算效率更高，也更节省内存。\n",
    "\n",
    "再举一些例子加深理解："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- [ ] A：(2d array): 5 x 4  \n",
    "- [ ] B：(1d array): 1  \n",
    "- [ ] Result：(2d array): 5 x 4  \n",
    "---\n",
    "- [ ] A：(2d array): 5 x 4   \n",
    "- [ ] B：(1d array): 4    \n",
    "- [ ] Result：(2d array): 5 x 4 \n",
    "---\n",
    "- [ ] A：(3d array): 15 x 3 x 5   \n",
    "- [ ] B：(3d array): 15 x 1 x 5  \n",
    "- [ ] Result：(3d array): 15 x 3 x 5\n",
    "---\n",
    "- [ ] A：(3d array): 15 x 3 x 5   \n",
    "- [ ] B：(2d array): 3 x 5   \n",
    "- [ ] Result：(3d array): 15 x 3 x 5\n",
    "---\n",
    "- [ ] A：(3d array): 15 x 3 x 5  \n",
    "- [ ] B：(2d array): 3 x 1  \n",
    "- [ ] Result：(3d array): 15 x 3 x 5"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "一些反例（不满足 Broadcasting 规则 ）："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- [ ] A (1d array): 3    \n",
    "- [ ] B (1d array): 4   \n",
    "---\n",
    "- [ ] A (2d array): 2 x 1    \n",
    "- [ ] B (3d array): 8 x 4 x 3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 5 范数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "范数是泛函分析中的概念，指的是一种更宽泛的长度（距离）概念，只要满足非负、自反、三角不等式就可以称之为距离。向量$v$的$p$范数可以使用下面公式进行计算：\n",
    "$$|v|{|_p} = {\\left[ {\\sum\\limits_{k = 1}^N {|{v_k}|p} } \\right]^{1/p}}$$\n",
    "当$p = 1,2$时分别叫做1范数，2范数。除此以外，还有无穷范数：\n",
    "$$|v|{|_{ + \\infty }} = \\max (|v(i)|)$$\n",
    "$$|v|{|_{ - \\infty }} = \\min (|v(i)|)$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tensorflow as tf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = tf.constant([[1.,2.],[1.,2.]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=4, shape=(), dtype=float32, numpy=6.0>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.norm(a, ord=1)  # 1范数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=10, shape=(), dtype=float32, numpy=3.1622777>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.norm(a, ord=2)  # 2范数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=16, shape=(), dtype=float32, numpy=3.1622777>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.norm(a)  # ord不指定时，默认是2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们也可以全手动地实现范数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=21, shape=(), dtype=float32, numpy=3.1622777>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.sqrt(tf.reduce_sum(tf.square(a)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "指定维度求范数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=27, shape=(2,), dtype=float32, numpy=array([1.4142135, 2.828427 ], dtype=float32)>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.norm(a, ord=2, axis=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=33, shape=(2,), dtype=float32, numpy=array([2.236068, 2.236068], dtype=float32)>"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.norm(a, ord=2, axis=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 参考"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[https://lufficc.com/blog/tensorflow-and-numpy-broadcasting](https://note.youdao.com/)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "study_python",
   "language": "python",
   "name": "study_python"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
